#include "structs.h"

/******************** LinkedList functions ********************/

LinkedList* HeadInsert(LinkedList* listHead, Edge* newEdge){

	LinkedList* temp;

	temp = (LinkedList*)malloc(sizeof(LinkedList));

	if(temp == NULL){
		perror("Error: standard function malloc has failed\n");
		return NULL;
	}

	temp->e = newEdge;
	temp->next = listHead;
	temp->prev = NULL;

	if (listHead != NULL)
		listHead->prev = temp;

	return temp;

}

LinkedList* DeleteItem(LinkedList* toDel){
	
	LinkedList* head;

	/*Delete Head*/
	if(toDel->prev == NULL){
		return DeleteHead(toDel);
	}		

	/*there is next*/
	if(toDel->next != NULL)
		toDel->next->prev = toDel->prev;

	toDel->prev->next = toDel->next;

	head = toDel;
	while(head->prev != NULL){
		head = head->prev;
	}

	free(toDel->e);
	free(toDel);

	return head;
}

LinkedList* DeleteHead(LinkedList* head){
	
	LinkedList* newHead;

	newHead = head->next;
	
	if(newHead != NULL){
		newHead->prev = NULL;
	}

	free(head->e);
	free(head);
	
	return newHead;


	/*newHead = (LinkedList*)malloc(sizeof(LinkedList));

	if(newHead == NULL){
		puts("Allocation Failed");
		exit(1);
	}

	newHead = head->next;
	
	if(newHead != NULL){
		newHead->prev = NULL;
	}

	free(head->e);
	free(head);

	return newHead;*/

}

LinkedList* getEdgeLink(LinkedList* head, int firstVertexID, int secondVertexID){

	Edge* temp = NULL;

	while (head != NULL){
		
		temp = head->e;
		
		if((temp->id1 == firstVertexID && temp->id2 == secondVertexID) || (temp->id2 == firstVertexID && temp->id1 == secondVertexID)){
			return head;
		}

		head = head->next;
	}

	return NULL;

}

void printList (LinkedList* list){

	while(list != NULL){

		printf("List Edges:\n");
		printf("id1, id2, weight: %d, %d, %f\n", list->e->id1, list->e->id2, list->e->weight);
		list = list->next;

	}
}


/******************** Network functions ********************/

Network* createNetwork(){

	Network* newNet = (Network*)malloc(sizeof(Network));

	if(newNet == NULL){
		perror("Error: standard function malloc has failed\n");
		return NULL;
	}

	newNet->vertices = (Vertex**)malloc(5*sizeof(Vertex*));

	if(newNet->vertices == NULL){
		perror("Error: standard function malloc has failed\n");
		return NULL;
	}

	newNet->maxSize = 5;
	newNet->size = 0;
	newNet->weightsSum = 0;
	newNet->totalEdgeNumber = 0;
	newNet->edge_list_head = NULL; /*G:new*/
	return newNet;

}

void printNet(Network* net){

	Vertex** v;
	Vertex* currV;
	int i;

	printf("net maxSize: %d\n", net->maxSize);
	printf("net size: %d\n", net->size);

	v = net->vertices;

	printf("vertices list:\n");
	for(i = 0; i<net->size; i++){
		
		currV = v[i];
		printf("vertex id, name, degree are: %d, %s, %d\n", currV->id, currV->name, currV->degree);

	}

}


/****************** Vertex functions ******************/

Vertex* createVertex(int id, char* newName){

	Vertex* newVer;
	char* name;
	int nameSize;

	newVer = (Vertex*)malloc(sizeof(Vertex));

	if(newVer == NULL){
		perror("Error: standard function malloc has failed\n");
		return NULL;
	}

	nameSize = strlen(newName);
	name = (char*)malloc(nameSize*sizeof(char));

	if(name == NULL){
		perror("Error: standard function malloc has failed\n");
		return NULL;
	}

	name = strcpy(name, newName);
	
	newVer->edges = NULL;
	newVer->degree = 0;
	newVer->id = id;
	newVer->name = name;

	return newVer;

}


/******************** Edge functions ********************/

Edge* createEdge(int id1, int id2, double weight){ 

	Edge* newEdge = (Edge*)malloc(sizeof(Edge));

	if(newEdge == NULL){
		perror("Error: standard function malloc has failed\n");
		return NULL;
	}

	newEdge->id1 = id1;
	newEdge->id2 = id2;
	newEdge->weight = weight;

	return newEdge;

}


/** G: Iterator functions **/

void init_iterator(Network *net, iterator *iter){ 
	int i=1;
	
	iter->network=net;
	iter->vertex_id=0; /* MUST VERIFY OR CHANGE */
	iter->currnet_vertex = net->vertices[0];
	iter->current_link = iter->currnet_vertex->edges;
	iter->currnet_edge = iter->current_link->e;
	iter->edge_array = (int*)malloc(1 + sizeof(int)*net->totalEdgeNumber*3); /*G: I don't use index 0; MUST FREE (via "terminate" !*/
	while(i<=net->totalEdgeNumber*3){
		iter->edge_array[i] = 0;
		i++;
	}
}

void terminate_iterator(iterator *iter){
	free(iter->edge_array);
}

int hasNext(iterator iter){ /* G: USE unsigned char ?*/
	if(iter.vertex_id==iter.network->size-1) return 0; /*G: See new network structure for +-1*/
	return 1;
};

void next_vertex(iterator *iter){
	
	if(!hasNext(*iter)) return;
	
	iter->vertex_id ++;
	iter->currnet_vertex = iter->network->vertices[iter->vertex_id];
	iter->current_link = iter->currnet_vertex->edges;
	iter->currnet_edge = iter->current_link->e;

}

/* Returns 1 if at least one edge remains for one of the remaining vertices, and 0 if not */
int hasNextEdge(iterator iter){

	Vertex **vertices = iter.network->vertices;
	Vertex *current_vertex = iter.currnet_vertex;
	int current_vertex_id = iter.vertex_id;
	int last_vertex = iter.network->size;

	if(iter.current_link==NULL) return 0;
	if(iter.current_link->next==NULL){         /*Go through all vertices untill finding an edge or out of vertices*/
		while(current_vertex_id<last_vertex-1){
			current_vertex_id++;
			current_vertex = vertices[current_vertex_id];
			if(current_vertex->edges!=NULL) return 1;
		}	
		return 0;
	}
	/* PAY ATTENTION: what to do if next edge is last and irelevant ???*/
	return 1;
}

/* this "next" function changes Vertices (increase)! */
void next_edge(iterator *iter){

	if(!hasNextEdge(*iter)){
		iter->current_link=NULL;
		iter->currnet_edge=NULL;
		return;
	}
	
	if(hasNextEdge(*iter)&&iter->current_link->next==NULL){
		while(hasNext(*iter)==1){
			next_vertex(iter);
			if(!hasNextEdge(*iter)){
				continue;
			}
			return;
		}
		return;
	}

	/* consider edges LOGIC/ORDER !!!*/

	iter->current_link = iter->current_link->next;
	iter->currnet_edge = iter->current_link->e;

}

/* NEW ITERATORS */

void new_vertex_iterator(Network *net, vertex_iterator *iter){
	iter->network = net;
	iter->currnet_vertex = iter->network->vertices[0];
	iter->cur_vertex_id = 0;
}

int hasNextVertex(vertex_iterator iter){
	if(iter.cur_vertex_id==iter.network->size-1) return 0; /*G: See new network structure for +-1*/
	return 1;
};

void next_vertex_NEW(vertex_iterator *iter){
	
	if(!hasNextVertex(*iter)) return;
	
	iter->cur_vertex_id ++;
	iter->currnet_vertex = iter->network->vertices[iter->cur_vertex_id];

}

void new_edge_iterator(Network *net, edge_iterator *iter){
	iter->network=net;
	iter->current_link = iter->network->edge_list_head;
	iter->currnet_edge = iter->current_link->e;
}

int hasNextEdge_NEW(edge_iterator iter){
	if(iter.current_link->next!=NULL) return 1;
	return 0;
}

void next_edge_NEW(edge_iterator *iter){
	
	if(iter->current_link->next!=NULL){
		iter->current_link = iter->current_link->next;
		iter->currnet_edge = iter->current_link->e;
	}
}

/*General iterator functions*/

void clean_iterator_index(vertex_iterator *ver_iter, edge_iterator *edge_iter){
	int i;
	Network *net = ver_iter->network; 
	Edge *cur_edge;

	for(i=0; i<net->size; i++){
		net->vertices[i]->indval_index = net->vertices[i]->matbeg_id; /*might pose some problem +-1*/
	}
	new_edge_iterator(net, edge_iter);
	while(hasNextEdge_NEW(*edge_iter)==1){
		cur_edge = edge_iter->currnet_edge;
		cur_edge->indval_index = cur_edge->matbeg_id;
		next_edge_NEW(edge_iter);
	}
}

void terminate_vertex_iterator(vertex_iterator *iter){
	/* I MUST IMPLEMENT */
}

void terminate_edge_iterator(edge_iterator *iter){
	/* I MUST IMPLEMENT */
}